package com.itheima.rpc.client.proxy;

import com.itheima.rpc.annotation.HrpcRemote;
import com.itheima.rpc.proxy.ProxyFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;

@Slf4j
@Component
//@DependsOn(value = "springBeanFactory")
public class RpcAnnotationProcessor implements BeanPostProcessor, ApplicationContextAware {

    private ProxyFactory proxyFactory;

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Field[] fields = bean.getClass().getDeclaredFields();
        for (Field field : fields) {
            if (!field.isAccessible()) {
                field.setAccessible(true);
            }
            HrpcRemote annotation = field.getAnnotation(HrpcRemote.class);
            if (annotation != null) {
                // 使用SpringBeanFactory.getBean()这种方式获取对象，必须加上@DependsOn(value = "springBeanFactory")
                // 确保springBeanFactory先初始化  但这种方式不提倡 会导致SpringBeanFactory跳过部分BeanPostProcessor被提前初始化 无法被自动代理（例如 AOP 动态代理）
                // 推荐使用implements ApplicationContextAware的方式提前获取ProxyFactory实例对象 但是ProxyFactory又不能走完所有BeanPostProcessor
//                proxyFactory = SpringBeanFactory.getBean(ProxyFactory.class);
                try {
                    // 创建代理对象
                    Object proxy = proxyFactory.newProxyInstance(field.getType());
                    // 将代理对象放入容器
                    field.set(bean, proxy);
                } catch (IllegalAccessException e) {
                    log.error("创建代理对象失败，fieldName={}，beanName={}， mes={}", field.getName(), bean.getClass().getName(), e.getMessage());
                    throw new RuntimeException(e);
                }
            }
        }
        return bean;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        proxyFactory = applicationContext.getBean(ProxyFactory.class);
    }
}
